/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.plechinger.mcremote.server.craft;

import java.io.*;
import java.util.Observable;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang3.StringUtils;

/**
 *
 * @author Lukas
 */
class CraftCommander extends Observable {

    private BufferedReader outputReader;
    private BufferedWriter commandWriter;
    private Process process;
    private static final Logger LOG = Logger.getLogger(CraftCommander.class.getName());
    private final File jarPath;
    private final String command;
    private NotifyThread notifyThread;
    private boolean started = false;

    private CraftCommander(File jarPath, String command) throws FileNotFoundException {
        if (jarPath.exists()) {
            this.jarPath = jarPath;
            this.command = command;
        } else {
            throw new FileNotFoundException("minecraft execution folder was not found");
        }
    }

    public void startServer() throws CraftServerStatusException {
        if(started){
            throw new CraftServerStatusException("Server is already running!");
        }
        try {

            Runtime runtime = Runtime.getRuntime();
            process = runtime.exec(command, null, jarPath);
            LOG.info("execute server-start-command " + command);
            outputReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            commandWriter = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));

            notifyThread = new NotifyThread(this);
            notifyThread.start();

            started = true;
        } catch (IOException ex) {
            Logger.getLogger(CraftCommander.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void stopServer() throws CraftServerStatusException{
        command(CraftCommand.SAVE_ALL);
        command(CraftCommand.STOP);
        try {
            Thread.sleep(5000);
        } catch (Exception e) {
        }
        started=false;
        
    }

    private int countParameters(CraftCommand command) {
        return StringUtils.countMatches(command.getCommand(), "%s");
    }

    public synchronized void command(CraftCommand command, String... parameters) throws CraftServerStatusException {
        if (!isStarted()) {
            throw new CraftServerStatusException("Minecraft is not started");
        }
        int commandNumber = countParameters(command);
        if (commandNumber != parameters.length) {
            throw new CraftCommandParameterException("Number of Parameters incorrect. Expected:" + parameters.length + " current:" + commandNumber);
        }

        String preparedCommand = String.format(command.getCommand(), (Object[]) parameters);
        try {
            commandWriter.append(preparedCommand);
            commandWriter.newLine();
            commandWriter.flush();

        } catch (IOException ex) {
            Logger.getLogger(CraftCommander.class.getName()).log(Level.SEVERE, null, ex);
            throw new CraftServerStatusException("Server was not able to start");
        }
    }

    public File getJarPath() {
        return jarPath;
    }

    public boolean isStarted() {
        return started;
    }

    public static CraftCommander build(File jarPath, String command) throws FileNotFoundException {
        return new CraftCommander(jarPath, command);
    }
    

    private class NotifyThread extends Thread {

        private CraftCommander parent;

        public NotifyThread(CraftCommander parent) {
            this.parent = parent;
        }

        @Override
        public void run() {
            try {
                String line = null;
                while ((line = outputReader.readLine()) != null && started) {
                    //System.out.println(line);
                    CraftLogElement element = new CraftLogElement(line);
                    parent.setChanged();
                    parent.notifyObservers(element);
                }
            } catch (IOException ex) {
                Logger.getLogger(CraftCommander.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}
